package scenic.toolkit;

import java.util.Vector;

import scenic.Graphics;
import scenic.SceneTransform;
import scenic.ScenicCanvas;
import scenic.geom.Affine2;
import scenic.geom.Double2;
import scenic.toolkit.db.NodeListener;
import scenic.toolkit.db.event.ChangeEvent;
import scenic.toolkit.event.MouseListener;

public class ComponentView implements View, NodeListener {
	private ComponentModel model;
	private ComponentView parent;
	private RootPane rootPane;
	private SceneTransform scene = new SceneTransform(Affine2.identity());
	private double width;
	private double height;
	private boolean isInvalid;
	private Vector<ComponentView> children = new Vector<ComponentView>();
	private Vector<MouseListener> mouseListeners = new Vector<MouseListener>();
	
	public ComponentView(ComponentModel model) {
		this.model = model;
		model.addListener(this);
		invalidate();
	}
	
	public Affine2 getTotalTransform() {
		if(parent == null)
			return getTransform();
		return parent.getTotalTransform().multiply(getTransform());
	}
	
	public void addMouseListener(MouseListener listener) {
		mouseListeners.add(listener);
	}
	
	public void removeMouseListener(MouseListener listener) {
		mouseListeners.remove(listener);
	}

	Vector<MouseListener> getMouseListeners() {
		return mouseListeners;
	}
	
	protected void addChild(ComponentView child) {
		if(child != null) {
			child.parent = this;
			children.add(child);
			child.invalidate();
		}
	}
	
	protected void removeChild(ComponentView child) {
		if(child != null)
		{
			child.parent = null;
			children.remove(child);
		}
	}
	
	protected Vector<ComponentView> getChildren() {
		return children;
	}
	
	public void changed(ChangeEvent event) {
		invalidate();
	}
	
	public ComponentModel getModel() {
		return model;
	}
	
	public ComponentView getParent() {
		return parent;
	}
	
	public void setParent(ComponentView parent) {
		this.parent = parent;
	}
	
	void setRootPane(RootPane rootPane) {
		this.rootPane = rootPane;
	}
	
	RootPane getRootPane() {
		if(parent != null)
			return parent.getRootPane();
		else
			return rootPane;
	}
	
	public SceneTransform getScene() {
		return scene;
	}	
	
	public double getWidth() {
		return width;
	}
	
	public void setWidth(double width) {
		this.width = width;
		invalidate();
	}
	
	public double getHeight() {
		return height;
	}
	
	public void setHeight(double height) {
		this.height = height;
		invalidate();
	}
	
	public void setSize(double width, double height) {
		this.width = width;
		this.height = height;
	}
	
	public Affine2 getTransform() {
		return scene.getTransform();
	}
	
	public void setTransform(Affine2 transform) {
		scene.setTransform(transform);
	}
	
	public ComponentView getChildAt(Double2 p) {
		for(int i = 0; i < children.size(); i++) {
			if(children.elementAt(i).isInside(p))
				return children.elementAt(i);
		}
		return null;
	}
	
	public boolean isInside(Double2 p) {
		Double2 p2 = getTransform().inverse().multiply(p);
		
		return p2.x >= 0 && p2.y >= 0 && p2.x < width && p2.y < height;
	}
	
	public void paint(Graphics g) {
	}
	
	void invalidate() {
		if(!isInvalid) {
			isInvalid = true;
		
			RootPane root = getRootPane();
		
			if(root != null)
				root.repaint();
		}
	}
	
	public void validate() {
		if(isInvalid) {
			paint(new Graphics(scene));
			isInvalid = false;
		}
		for(ComponentView c : children)
			c.validate();
	}
}
